﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="EntityHydrator.cs" company="Data Ductus Malmö">
//   (c) 2010 - 2012 Data Ductus Malmö AB
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace DataDuctus.Snmp.Persistor.Core.Persistor.Internal
{
  using System.Collections.Generic;

  using DataDuctus.Snmp.Persistor.Core.MetaData;

  using Lextm.SharpSnmpLib;

  /// <summary>
  /// The entity hydrator.
  /// </summary>
  internal class EntityHydrator
  {
    #region Methods

    /// <summary>
    /// The hydrate.
    /// </summary>
    /// <param name="variables">
    /// The variables.
    /// </param>
    /// <param name="clzType">
    /// The clz type.
    /// </param>
    /// <typeparam name="T">
    /// </typeparam>
    /// <returns>
    /// The System.Collections.Generic.IEnumerable`1[T -&gt; T].
    /// </returns>
    internal static IEnumerable<T> Hydrate<T>(IList<Variable> variables, ClassMeta clzType) where T : new()
    {
      return clzType.IsTable ? HydrateTable<T>(variables, clzType) : HydrateScalars<T>(variables, clzType);
    }

    /// <summary>
    /// The extract sub oid.
    /// </summary>
    /// <param name="oid">
    /// The oid.
    /// </param>
    /// <param name="baseOidLen">
    /// The base oid len.
    /// </param>
    /// <returns>
    /// The System.Int32.
    /// </returns>
    private static int ExtractSubOid(string oid, int baseOidLen)
    {
      string rest = oid.Substring(baseOidLen + 2);

      int idx = rest.IndexOf('.');

      if (-1 == idx)
      {
        return int.Parse(rest);
      }

      return int.Parse(rest.Substring(0, idx));
    }

    /// <summary>
    /// The hydrate scalars.
    /// </summary>
    /// <param name="variables">
    /// The variables.
    /// </param>
    /// <param name="clzType">
    /// The clz type.
    /// </param>
    /// <typeparam name="T">
    /// </typeparam>
    /// <returns>
    /// The System.Collections.Generic.IEnumerable`1[T -&gt; T].
    /// </returns>
    private static IEnumerable<T> HydrateScalars<T>(IEnumerable<Variable> variables, ClassMeta clzType) where T : new()
    {
      int baseOidLen = clzType.Oid.Length;

      var res = new T();

      foreach (Variable variable in variables)
      {
        int leafIndex = ExtractSubOid(variable.Id.ToString(), baseOidLen);

        Reflector.SetProperty(leafIndex, clzType, res, variable.Data);
      }

      return new[] { res };
    }

    /// <summary>
    /// The hydrate table.
    /// </summary>
    /// <param name="variables">
    /// The variables.
    /// </param>
    /// <param name="clzType">
    /// The clz type.
    /// </param>
    /// <typeparam name="T">
    /// </typeparam>
    /// <returns>
    /// The System.Collections.Generic.IEnumerable`1[T -&gt; T].
    /// </returns>
    private static IEnumerable<T> HydrateTable<T>(IList<Variable> variables, ClassMeta clzType) where T : new()
    {
      int baseOidLen = clzType.Oid.Length;

      int cnt = variables.Count / clzType.Properties.Count;

      var ret = new T[cnt];

      for (int i = 0; i < cnt; i++)
      {
        ret[i] = new T();
      }

      int index = 0;

      foreach (Variable variable in variables)
      {
        if (index == cnt)
        {
          index = 0;
        }

        int column = ExtractSubOid(variable.Id.ToString(), baseOidLen);

        Reflector.SetProperty(column, clzType, ret[index], variable.Data);

        index++;
      }

      return ret;
    }

    #endregion
  }
}